PoC/iOS/Bluetooth Tracing PoC/Sources/Services/NotificationService.swift (79 lines of code) (raw):

// ========================================================================= // Copyright 2020 EPAM Systems, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========================================================================= import UIKit import UserNotifications extension Notification.Name { static let RestartBluetooth = Notification.Name(rawValue: "RestartBluetoothNotification") } /* Service that provides authorisation for local notifications and displaying notification messages with actions for restarting Bluetooth stack (immediately or by schedule) */ class NotificationService: NSObject, UNUserNotificationCenterDelegate { private enum Constants { static let backgroundRefreshInterval = 3600.0 static let restartNotificationTimeInterval = 300.0 static let acitonNotificationHour = 16 static let categoryRestart = "com.tazetdinov.notification.category.restart" static let categoryShowRestart = "com.tazetdinov.notification.category.show-restart" static let actionRestart = "com.tazetdinov.notification.action.force-restart" static let actionShowRestart = "com.tazetdinov.notification.action.show-restart" } static let shared = NotificationService() private override init() { super.init() UNUserNotificationCenter.current().delegate = self } func authorize() { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { _, _ in } } func show(message: String) { setupCategories() let content = UNMutableNotificationContent() content.categoryIdentifier = Constants.categoryRestart content.title = "BT message" content.body = message content.sound = .default let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil) UNUserNotificationCenter.current().add(request) } private func scheduleActionNotification() { let trigger = UNTimeIntervalNotificationTrigger(timeInterval: Constants.restartNotificationTimeInterval, repeats: false) showRestartNotification(trigger: trigger) } private func showRestartNotification(trigger: UNNotificationTrigger) { setupCategories() let content = UNMutableNotificationContent() content.categoryIdentifier = Constants.categoryRestart content.title = "Workaround for BT Background" content.body = "Let's restart bluetooth stack?" content.sound = .default let request = UNNotificationRequest(identifier: Constants.categoryRestart, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request, withCompletionHandler: nil) } private func setupCategories() { UIApplication.shared.setMinimumBackgroundFetchInterval(Constants.backgroundRefreshInterval) let options: UNNotificationCategoryOptions = [.customDismissAction, .hiddenPreviewsShowTitle, .hiddenPreviewsShowSubtitle] let restartAction = UNNotificationAction(identifier: Constants.actionRestart, title: "Restart BT") let restartActionCategory = UNNotificationCategory(identifier: Constants.categoryRestart, actions: [restartAction], intentIdentifiers: [], options: options) let showAction = UNNotificationAction(identifier: Constants.actionShowRestart, title: "Schedule restart BT") let showActionCategory = UNNotificationCategory(identifier: Constants.categoryRestart, actions: [showAction], intentIdentifiers: [], options: options) UNUserNotificationCenter.current().setNotificationCategories([restartActionCategory, showActionCategory]) } // MARK: - UNUserNotificationCenterDelegate func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { switch response.actionIdentifier { case Constants.actionRestart: NotificationCenter.default.post(name: .RestartBluetooth, object: self) case Constants.actionShowRestart: self.scheduleActionNotification() default: break } completionHandler() } }